import {Buffer} from "buffer";
import {AxdrSequenceOf} from "../asn1.axdr/AxdrSequenceOf";
import {Unsigned8} from "./Unsigned8";
import {Unsigned16} from "./Unsigned16";
import {TSA} from "./TSA";
import {Region} from "./Region";
import {AxdrNull} from "../asn1.axdr/AxdrNull";
import {AxdrType} from "../asn1.axdr/AxdrType";
import {ReverseByteArrayInputStream} from "../ReverseByteArrayInputStream";
import {ReverseByteArrayOutputStream} from "../ReverseByteArrayOutputStream";
import {AxdrEnum} from "../asn1.axdr/AxdrEnum";


export class SubSeqOfUnsigned8 extends AxdrSequenceOf<Unsigned8>{

    createListElement(): Unsigned8 {
        let u8 = new Unsigned8();
        u8.set_const();
        return u8;
    }

    constructor() {
        super();
    }

}

export class SubSeqOfUnsigned16 extends AxdrSequenceOf<Unsigned16>{

    createListElement(): Unsigned16 {
        let u16 = new Unsigned16();
        u16.set_const();
        return u16;
    }

    constructor() {
        super();
    }

}

export class SubSeqOfTsa extends AxdrSequenceOf<TSA>{

    createListElement(): TSA {
        return new TSA();
    }

    constructor() {
        super();
    }

}

export class SubSeqOfRegion extends AxdrSequenceOf<Region>{

    createListElement(): Region {
        return new Region();
    }

    constructor() {
        super();
    }

}

enum Choice {
    _ERR_NONE_SELECTED = -1,
    NOM = 0 ,
    ALLMADDR = 1,
    GROUPMTYPE = 2,
    GROUPMADDR = 3,
    GROUPSETINDEX = 4,
    REGIONTYPE = 5,
    REGIONADDR = 6,
    REGIONSETINDEX = 7
}

export class MS implements AxdrType{

    dataCode : Buffer | null = null;
    choice : Choice = Choice._ERR_NONE_SELECTED;
    nom : AxdrNull | null = null;
    allmaddr : AxdrNull | null = null;
    groupmtype : SubSeqOfUnsigned8 | null = null;
    groupmaddr : SubSeqOfTsa | null = null;
    groupsetindex : SubSeqOfUnsigned16 | null = null;
    regiontype : SubSeqOfRegion | null = null;
    regionaddr : SubSeqOfRegion | null = null
    regionsetindex : SubSeqOfRegion | null = null;


    constructor() {

    }

    set_dataCode(dataCode : Buffer){
        this.dataCode = dataCode;
    }

    decode(input: ReverseByteArrayInputStream): number {
        let codeLength = 0;
        let choosen = new AxdrEnum();
        choosen.set_const();

        codeLength += choosen.decode(input);
        this.resetChoices();
        this.choice = choosen.getValue();

        if (this.choice == Choice.NOM) {
            this.nom = new AxdrNull();
            codeLength += this.nom.decode(input);
            return codeLength;
        }

        if (this.choice == Choice.ALLMADDR) {
            this.allmaddr = new AxdrNull();
            codeLength += this.allmaddr.decode(input);
            return codeLength;
        }

        if (this.choice == Choice.GROUPMTYPE) {
            this.groupmtype = new SubSeqOfUnsigned8();
            codeLength += this.groupmtype.decode(input);
            return codeLength;
        }

        if (this.choice == Choice.GROUPMADDR) {
            this.groupmaddr = new SubSeqOfTsa();
            codeLength += this.groupmaddr.decode(input);
            return codeLength;
        }

        if (this.choice == Choice.GROUPSETINDEX) {
            this.groupsetindex = new SubSeqOfUnsigned16();
            codeLength += this.groupsetindex.decode(input);
            return codeLength;
        }

        if (this.choice == Choice.REGIONTYPE) {
            this.regiontype = new SubSeqOfRegion();
            codeLength += this.regiontype.decode(input);
            return codeLength;
        }

        if (this.choice == Choice.REGIONADDR) {
            this.regionaddr = new SubSeqOfRegion();
            codeLength += this.regionaddr.decode(input);
            return codeLength;
        }

        if (this.choice == Choice.REGIONSETINDEX) {
            this.regionsetindex = new SubSeqOfRegion();
            codeLength += this.regionsetindex.decode(input);
            return codeLength;
        }

        throw new Error("Error decoding AxdrChoice: Identifier matched to no item.");
    }

    encode(output: ReverseByteArrayOutputStream): number {
        if (this.dataCode != null) {
            for (let i = this.dataCode.length - 1; i >= 0; i--) {
                output.write(this.dataCode[i]);
            }
            return this.dataCode.length;

        }
        if (this.choice == Choice._ERR_NONE_SELECTED) {
            throw new Error("Error encoding AxdrChoice: No item in choice was selected.");
        }

        let codeLength = 0;

        if (this.choice == Choice.REGIONSETINDEX) {
            codeLength += this.regionsetindex.encode(output);
            let c = new AxdrEnum();
            c.set_min_max_val(7);
            codeLength += c.encode(output);
            return codeLength;
        }

        if (this.choice == Choice.REGIONADDR) {
            codeLength += this.regionaddr.encode(output);
            let c = new AxdrEnum();
            c.set_min_max_val(6)
            codeLength += c.encode(output);
            return codeLength;
        }

        if (this.choice == Choice.REGIONTYPE) {
            codeLength += this.regiontype.encode(output);
            let c = new AxdrEnum();
            c.set_min_max_val(5)
            codeLength += c.encode(output);
            return codeLength;
        }

        if (this.choice == Choice.GROUPSETINDEX) {
            codeLength += this.groupsetindex.encode(output);
            let c = new AxdrEnum();
            c.set_min_max_val(4)
            codeLength += c.encode(output);
            return codeLength;
        }

        if (this.choice == Choice.GROUPMADDR) {
            codeLength += this.groupmaddr.encode(output);
            let c = new AxdrEnum();
            c.set_min_max_val(3);
            codeLength += c.encode(output);
            return codeLength;
        }

        if (this.choice == Choice.GROUPMTYPE) {
            codeLength += this.groupmtype.encode(output);
            let c = new AxdrEnum();
            c.set_min_max_val(2);
            codeLength += c.encode(output);
            return codeLength;
        }

        if (this.choice == Choice.ALLMADDR) {
            codeLength += this.allmaddr.encode(output);
            let c = new AxdrEnum();
            c.set_min_max_val(1)
            codeLength += c.encode(output);
            return codeLength;
        }

        if (this.choice == Choice.NOM) {
            codeLength += this.nom.encode(output);
            let c = new AxdrEnum();
            c.set_min_max_val(0)
            codeLength += c.encode(output);
            return codeLength;
        }

        throw new Error("Error encoding AxdrChoice: No item in choice was encoded.");
    }

    resetChoices(){
        this.choice = Choice._ERR_NONE_SELECTED;
        this.nom = null;
        this.allmaddr = null;
        this.groupmtype = null;
        this.groupmaddr = null;
        this.groupsetindex = null;
        this.regiontype = null;
        this.regionaddr = null;
        this.regionsetindex = null;
    }

    encodeAndSave(encodingSizeGuess: number) {
        let revOStream = new ReverseByteArrayOutputStream();
        revOStream.setBufSize(encodingSizeGuess);
        this.encode(revOStream);
        this.dataCode = revOStream.getArray();
    }

    getChoiceIndex() : Choice{
        return this.choice;
    }

    setNom(nom : AxdrNull){
        this.resetChoices();
        this.choice = Choice.NOM;
        this.nom = nom;
    }

    setAllmaddr(allmaddr : AxdrNull){
        this.resetChoices();
        this.choice = Choice.ALLMADDR;
        this.allmaddr = allmaddr;
    }

    setGroupmtype(groupmtype : SubSeqOfUnsigned8){
        this.resetChoices();
        this.choice = Choice.GROUPMTYPE;
        this.groupmtype = groupmtype;
    }

    setGroupmaddr(groupmaddr : SubSeqOfTsa){
        this.resetChoices();
        this.choice = Choice.GROUPMADDR;
        this.groupmaddr = groupmaddr;
    }

    setGroupsetindex(groupsetindex : SubSeqOfUnsigned16){
        this.resetChoices();
        this.choice = Choice.GROUPSETINDEX;
        this.groupsetindex = groupsetindex;
    }

    setRegiontype(regiontype : SubSeqOfRegion){
        this.resetChoices();
        this.choice = Choice.REGIONTYPE;
        this.regiontype = regiontype;
    }

    setRegionaddr(regionaddr : SubSeqOfRegion){
        this.resetChoices();
        this.choice = Choice.REGIONADDR;
        this.regionaddr = regionaddr;
    }

    setRegionsetindex(regionsetindex : SubSeqOfRegion){
        this.resetChoices();
        this.choice = Choice.REGIONSETINDEX;
        this.regionsetindex = regionsetindex;
    }

    toString(): string {
        if (this.choice == Choice.NOM) {
            if (this.nom != null) {
                return "choice: {nom: " + this.nom + "}";
            } else {
                return "choice is nom but nom is null";
            }
        }else if(this.choice == Choice.ALLMADDR){
            if(this.allmaddr != null){
                return "choice: {allmaddr: " + this.allmaddr + "}";
            }else{
                return "choice is allmaddr but allmaddr is null";
            }
        }else if(this.choice == Choice.GROUPMTYPE){
            if(this.groupmtype != null){
                return "choice: {groupmtype: " + this.groupmtype + "}";
            }else{
                return "choice is groupmtype but groupmtype is null";
            }
        }else if(this.choice == Choice.GROUPMADDR){
            if(this.groupmaddr != null){
                return "choice: {groupmaddr: " + this.groupmaddr + "}";
            }else{
                return "choice is groupmaddr but groupmaddr is null";
            }
        }else if(this.choice == Choice.GROUPSETINDEX){
            if(this.groupsetindex != null){
                return "choice: {groupsetindex: " + this.groupsetindex + "}";
            }else{
                return "choice is groupsetindex but groupsetindex is null";
            }
        }else if(this.choice == Choice.REGIONTYPE){
            if(this.regiontype != null){
                return "choice: {regiontype: " + this.regiontype + "}";
            }else{
                return "choice is regiontype but regiontype is null";
            }
        }else if(this.choice == Choice.REGIONADDR){
            if(this.regionaddr != null){
                return "choice: {regionaddr: " + this.regionaddr + "}";
            }else{
                return "choice is regionaddr but regionaddr is null";
            }
        }else if(this.choice == Choice.REGIONSETINDEX){
            if(this.regionsetindex != null){
                return "choice: {regionsetindex: " + this.regionsetindex + "}";
            }else{
                return "choice is regionsetindex but regionsetindex is null";
            }
        } else {
            return "unknown";
        }
    }

}
